package com.yxy.springcloud.framework.unionauth.service;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Maps;
import com.yxy.springcloud.framework.common.base.BusinessException;
import com.yxy.springcloud.framework.common.base.PageDataList;
import com.yxy.springcloud.framework.common.redis.RedisUtils;
import com.yxy.springcloud.framework.unionauth.DTO.DataDicItemsCreateDto;
import com.yxy.springcloud.framework.unionauth.DTO.DataDicItemsQueryDto;
import com.yxy.springcloud.framework.unionauth.DTO.DataDicQueryDto;
import com.yxy.springcloud.framework.unionauth.dao.AppDataDicChangedMapper;
import com.yxy.springcloud.framework.unionauth.dao.AppDataDicDetailMapper;
import com.yxy.springcloud.framework.unionauth.dao.AppDataDicMapper;
import com.yxy.springcloud.framework.unionauth.dao.AppMapper;
import com.yxy.springcloud.framework.unionauth.model.*;
import com.yxy.springcloud.framework.unionauth.utils.TokenCheckUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.*;

@Service
public class DataDicService {
  @Autowired
  private TokenCheckUtil tokenCheckUtil;

  @Autowired
  private RedisUtils redisUtils;

  @Resource
  private AppDataDicMapper appDataDicMapper;

  @Resource
  private AppMapper appMapper;

  @Resource
  private AppDataDicDetailMapper appDataDicDetailMapper;

  @Resource
  private AppDataDicChangedMapper appDataDicChangedMapper;

  public PageDataList<AppDataDic> getList(@Valid DataDicQueryDto query) {
    List<AppDataDic> resultList = new ArrayList<>();

    PageHelper.startPage(query.getPageNumber(), query.getPageSize());
    PageHelper.orderBy("t1.create_date desc");//排序
    List<AppDataDic> dbResult = appDataDicMapper.selectList(query);

    Page<AppDataDic> dbResultPage = (Page<AppDataDic>) dbResult;

    for (AppDataDic dbItem : dbResultPage.getResult()) {
      resultList.add(dbItem);
    }

    PageDataList<AppDataDic> pageDataList = new PageDataList<>(dbResultPage.getTotal(),
            dbResultPage.getPages(),
            dbResultPage.getPageNum(), dbResultPage.getPageSize());
    pageDataList.setList(resultList);
    return pageDataList;
  }

  //逻辑删除
  public void delete(long id) throws BusinessException {
    String curUserStr = tokenCheckUtil.getUserInfoByToken();
    AuthAdminUser curUser = JSON.parseObject(curUserStr, AuthAdminUser.class);

    AppDataDic updateObj = new AppDataDic();
    updateObj.setId(id);
    updateObj.setStatus(1L);
    updateObj.setUpdateDate(new Date());
    updateObj.setUpdateUserId(curUser.getId());
    updateObj.setUpdateUserName(curUser.getUsername());
    appDataDicMapper.updateByPrimaryKeySelective(updateObj);
  }

  @Transactional(rollbackFor = Exception.class)
  public Map<String, Object> createOrUpdate(AppDataDic inputDto) throws BusinessException {
    Map<String, Object> resultMap = new HashMap<>();
    String curUserStr = tokenCheckUtil.getUserInfoByToken();
    AuthAdminUser loginUser = JSON.parseObject(curUserStr, AuthAdminUser.class);

    Long id = inputDto.getId();
    if (id == null) { // insert
      AppDataDic insertObj = new AppDataDic();
      BeanUtils.copyProperties(inputDto, insertObj);
      InsertBaseEntity baseEntity = new InsertBaseEntity(loginUser.getId(), loginUser.getName());
      BeanUtils.copyProperties(baseEntity, insertObj);
      appDataDicMapper.insertSelective(insertObj);
      resultMap.put("id", insertObj.getId());
    } else { //update
      AppDataDic updateObj = new AppDataDic();
      BeanUtils.copyProperties(inputDto, updateObj);
      updateObj.setId(id);
      updateObj.setUpdateUserId(loginUser.getId());
      updateObj.setUpdateUserName(loginUser.getName());
      updateObj.setUpdateDate(new Date());
      appDataDicMapper.updateByPrimaryKeySelective(updateObj);
      resultMap.put("id", id);
    }
    // 记录到 app_data_dic_changed表,标志 app的数据字典已经改变, 需要 懒加载时进行同步到redis
    AppDataDicChanged queryObj = new AppDataDicChanged();
    queryObj.setAppId(inputDto.getAppId());
    AppDataDicChanged dbObj = appDataDicChangedMapper.selectOne(queryObj);
    if (dbObj == null) { //insert
      AppDataDicChanged insertObj = new AppDataDicChanged();
      insertObj.setAppId(inputDto.getAppId());
      insertObj.setChanged(1L);
      InsertBaseEntity baseEntity = new InsertBaseEntity(loginUser.getId(), loginUser.getName());
      BeanUtils.copyProperties(baseEntity, insertObj);
      appDataDicChangedMapper.insertSelective(insertObj);
    } else { // update
      AppDataDicChanged updateObj = new AppDataDicChanged();
      updateObj.setId(dbObj.getId());
      updateObj.setChanged(1L);
      updateObj.setUpdateDate(new Date());
      updateObj.setUpdateUserId(loginUser.getId());
      updateObj.setUpdateUserName(loginUser.getUsername());
      appDataDicChangedMapper.updateByPrimaryKeySelective(updateObj);
    }
    return resultMap;
  }

  @Transactional(rollbackFor = Exception.class)
  // return HashMap<String, List> key为字典的code, value是字典项列表按照order2排序
  public Object getDataDicByApp(String appName) throws BusinessException {
    App appQueryObj = new App();
    appQueryObj.setName(appName);
    appQueryObj.setStatus(0L);
    App appDB = appMapper.selectOne(appQueryObj);
    if (appDB == null) {
      throw new BusinessException(531, "app不存在");
    }
    long appId = appDB.getId();

    AppDataDicChanged queryObj = new AppDataDicChanged();
    queryObj.setAppId(appId);
    AppDataDicChanged changedObj = appDataDicChangedMapper.selectOne(queryObj);
    if (changedObj == null) {//插入默认记录
      AppDataDicChanged insertObjOrig = new AppDataDicChanged();
      insertObjOrig.setAppId(appId);
      insertObjOrig.setChanged(0L);
      appDataDicChangedMapper.insertSelective(insertObjOrig);
      changedObj = insertObjOrig;
    }

    String redisKey = appName + "#dic";
    String dicJsonString = redisUtils.get(redisKey);
    if (dicJsonString == null) {// redis为空, 需要先同步
      return this.syncDataDicToRedis(appName, appId);
    }
    // redis不为空, 需要检查 app_data_dic_changed表, 查看数据字典是否有变化
    long changed = changedObj.getChanged();
    if (changed == 0L) {// 数据字典没有改变, 从redis中读取并返回
      if (StringUtils.isEmpty(dicJsonString)) {
        return Maps.newHashMap();
      } else {
        return JSON.parse(dicJsonString);
      }
    } else {//数据字典有改变
      AppDataDicChanged updateObj = new AppDataDicChanged();
      updateObj.setId(changedObj.getId());
      updateObj.setChanged(1L);
      appDataDicChangedMapper.updateByPrimaryKeySelective(updateObj);
      return this.syncDataDicToRedis(appName, appId);
    }
  }

  // 同步app字典数据到redis
  private HashMap<String, List> syncDataDicToRedis(String appName, long appId) {
    String redisKey = appName + "#dic";
    // 首先删除redis key
    redisUtils.del(redisKey);

    AppDataDic queryObj = new AppDataDic();
    queryObj.setAppId(appId);
    queryObj.setStatus(0L);
    List<AppDataDic> parentList = appDataDicMapper.select(queryObj);
    HashMap<String, List> dicMap = new HashMap<>();
    for (AppDataDic parent: parentList) {
      //查询字典列表项
      long parentId = parent.getId();
      List<AppDataDicDetail> dicDetailList = appDataDicDetailMapper.selectList(parentId);
      dicMap.put(parent.getCode(), dicDetailList);
    }
    redisUtils.set(redisKey, JSON.toJSONString(dicMap));
    return dicMap;
  }

  public PageDataList<AppDataDicDetail> getDicItems(long id, DataDicItemsQueryDto query) {
    List<AppDataDicDetail> resultList = new ArrayList<>();

    PageHelper.startPage(query.getPageNumber(), query.getPageSize());
    PageHelper.orderBy("order2 asc");//排序

    AppDataDicDetail queryObj = new AppDataDicDetail();
    queryObj.setParentId(id);
    queryObj.setStatus(0L);
    BeanUtils.copyProperties(query, queryObj);
    List<AppDataDicDetail> dbResult = appDataDicDetailMapper.select(queryObj);

    Page<AppDataDicDetail> dbResultPage = (Page<AppDataDicDetail>) dbResult;

    for (AppDataDicDetail dbItem : dbResultPage.getResult()) {
      resultList.add(dbItem);
    }

    PageDataList<AppDataDicDetail> pageDataList = new PageDataList<>(dbResultPage.getTotal(),
            dbResultPage.getPages(),
            dbResultPage.getPageNum(), dbResultPage.getPageSize());
    pageDataList.setList(resultList);
    return pageDataList;
  }

  @Transactional(rollbackFor = Exception.class)
  public Map<String, Object> createOrUpdateDicItems(long parentId, DataDicItemsCreateDto inputDto) throws BusinessException {
    Map<String, Object> resultMap = new HashMap<>();
    String curUserStr = tokenCheckUtil.getUserInfoByToken();
    AuthAdminUser loginUser = JSON.parseObject(curUserStr, AuthAdminUser.class);

    Long itemId = inputDto.getId();
    if (itemId == null) { // insert
      AppDataDicDetail insertObj = new AppDataDicDetail();
      BeanUtils.copyProperties(inputDto, insertObj);
      insertObj.setParentId(parentId);
      InsertBaseEntity baseEntity = new InsertBaseEntity(loginUser.getId(), loginUser.getName());
      BeanUtils.copyProperties(baseEntity, insertObj);
      appDataDicDetailMapper.insertSelective(insertObj);
      resultMap.put("id", insertObj.getId());
    } else { //update
      AppDataDicDetail updateObj = new AppDataDicDetail();
      BeanUtils.copyProperties(inputDto, updateObj);
      updateObj.setId(itemId);
      updateObj.setUpdateUserId(loginUser.getId());
      updateObj.setUpdateUserName(loginUser.getName());
      updateObj.setUpdateDate(new Date());
      appDataDicDetailMapper.updateByPrimaryKeySelective(updateObj);
      resultMap.put("id", itemId);
    }
    // 记录到 app_data_dic_changed表,标志 app的数据字典已经改变, 需要 懒加载时进行同步到redis
    Long appId = appDataDicMapper.selectByPrimaryKey(parentId).getAppId();
    AppDataDicChanged queryObj = new AppDataDicChanged();
    queryObj.setAppId(appId);
    AppDataDicChanged dbObj = appDataDicChangedMapper.selectOne(queryObj);
    if (dbObj == null) { //insert
      AppDataDicChanged insertObj = new AppDataDicChanged();
      insertObj.setAppId(appId);
      insertObj.setChanged(1L);
      InsertBaseEntity baseEntity = new InsertBaseEntity(loginUser.getId(), loginUser.getName());
      BeanUtils.copyProperties(baseEntity, insertObj);
      appDataDicChangedMapper.insertSelective(insertObj);
    } else { // update
      AppDataDicChanged updateObj = new AppDataDicChanged();
      updateObj.setId(dbObj.getId());
      updateObj.setChanged(1L);
      updateObj.setUpdateDate(new Date());
      updateObj.setUpdateUserId(loginUser.getId());
      updateObj.setUpdateUserName(loginUser.getUsername());
      appDataDicChangedMapper.updateByPrimaryKeySelective(updateObj);
    }
    return resultMap;

  }

  public void deleteItem(long itemId) throws BusinessException{
    String curUserStr = tokenCheckUtil.getUserInfoByToken();
    AuthAdminUser curUser = JSON.parseObject(curUserStr, AuthAdminUser.class);

    AppDataDicDetail updateObj = new AppDataDicDetail();
    updateObj.setId(itemId);
    updateObj.setStatus(1L);
    updateObj.setUpdateDate(new Date());
    updateObj.setUpdateUserId(curUser.getId());
    updateObj.setUpdateUserName(curUser.getUsername());
    appDataDicDetailMapper.updateByPrimaryKeySelective(updateObj);
  }

  public AppDataDicDetail getDataDicDetailById(Long id) {
    return appDataDicDetailMapper.selectByPrimaryKey(id);
  }

  public AppDataDicDetail getDataDicDetailByValue(String appCode, String value) {
    String[] tmp = value.split("\\.");
    return appDataDicDetailMapper.getDataDicDetailByValue(appCode, tmp[0], tmp[1]);
  }
}
